package com.uraurora.crescent.function;

import com.google.common.cache.Cache;
import com.uraurora.crescent.function.functools.memoizer.MemoizerFunc5;
import com.uraurora.crescent.tuple.ITuple;

import java.util.Objects;
import java.util.concurrent.Future;

@FunctionalInterface
public interface Func5<T1, T2, T3, T4, T5, RT> {

    RT on(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5);

    default <V> Func5<T1, T2, T3, T4, T5, V> after(Func1<? super RT, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) -> after.on(on(t1, t2, t3, t4, t5));
    }

    default Func4<T2, T3, T4, T5, RT> curry1(T1 t1){
        return (t2, t3, t4, t5) -> on(t1, t2, t3, t4, t5);
    }

    default Func4<T1, T3, T4, T5, RT> curry2(T2 t2){
        return (t1, t3, t4, t5) -> on(t1, t2, t3, t4, t5);
    }

    default Func4<T1, T2, T4, T5, RT> curry3(T3 t3){
        return (t1, t2, t4, t5) -> on(t1, t2, t3, t4, t5);
    }

    default Func4<T1, T2, T3, T5, RT> curry4(T4 t4){
        return (t1, t2, t3, t5) -> on(t1, t2, t3, t4, t5);
    }

    default Func4<T1, T2, T3, T4, RT> curry5(T5 t5){
        return (t1, t2, t3, t4) -> on(t1, t2, t3, t4, t5);
    }



    default Func1<T5, RT> curry(T1 t1, T2 t2, T3 t3, T4 t4){
        return t5 -> on(t1, t2, t3, t4, t5);
    }

    default Func2<T4, T5, RT> curry(T1 t1, T2 t2, T3 t3){
        return (t4, t5) -> on(t1, t2, t3, t4, t5);
    }

    default Func3<T3, T4, T5, RT> curry(T1 t1, T2 t2){
        return (t3, t4, t5) -> on(t1, t2, t3, t4, t5);
    }


    //<editor-fold desc="记忆化">
    default MemoizerFunc5<T1, T2, T3, T4, T5, RT> memoize(){
        return new MemoizerFunc5<>(this);
    }

    default MemoizerFunc5<T1, T2, T3, T4, T5, RT> memoize(Cache<ITuple, Future<RT>> cache){
        return new MemoizerFunc5<>(this, cache);
    }
    //</editor-fold>

}
